/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.webos.java.jabber.chat;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.json.JSONArray;
import org.json.JSONObject;
import org.webos.java.base.Frame;
import org.webos.java.base.FrameType;
import org.webos.java.base.Notify;
import org.webos.java.base.RemoteMessage;
import org.webos.java.base.workspace.Workspace;
import org.webos.java.jabber.JabberApp;
import org.webos.java.jabber.tree.ConnectionItem;
import org.webos.java.jabber.tree.UserItem;
import org.webos.java.root.Log;
import org.webos.java.base.NetworkManager;
import org.webos.java.base.SystemManager;

/**
 *
 * @author Kostya
 */

@FrameType(code="chat-frame", jsClass="jabber.Chat")
public class ChatFrame extends Frame{

    private static final String URL_REGEXP = "((https?:\\/\\/|www\\.)([-\\w\\.]+)+(:\\d+)?(\\/([\\w\\/_\\.-]*(\\?\\S+)?)?)?)";
    private static final String URL_REGEXP2 = "((https?|ftp)\\://((\\[?(\\d{1,3}\\.){3}\\d{1,3}\\]?)|(([-a-zA-Z0-9]+\\.)+[a-zA-Z]{2,6}))(\\:\\d+)?(/[-a-zA-Z0-9._\\?,'+\\&\\%\\$\\#=~\\\\\\;/]+)*)";
    String frameTitle = "";
    String connectionID = "";
    String toJID = "";
    String fromUserName = "";
    String toUserName = "";
    List<ChatMessage> messages = new ArrayList<ChatMessage>();
    JabberApp jabberApp = null;
    int newMessages = 0;
    SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM HH:mm:ss");
    SimpleDateFormat mobileDateFormat = new SimpleDateFormat("HH:mm");
    SimpleDateFormat mobileDateFormatArchived = new SimpleDateFormat("dd/MM HH:mm");
    boolean historyRequested = false;
    ConnectionItem connectionItem = null;

    public ChatFrame(JabberApp app, Workspace aWorkspace, 
            ConnectionItem aConnectionItem, String aUserName, String aUserJID) {
        super(app, aWorkspace);
        connectionItem = aConnectionItem;
        jabberApp = app;
        frameTitle = aUserName+" - "+aConnectionItem.getNickName();
        connectionID = aConnectionItem.getId();
        toJID = aUserJID;
        toUserName = aUserName;
        fromUserName = aConnectionItem.getUserName();
        setCode(toJID+aConnectionItem.getUserName());
        setTitle(frameTitle);
        setCloseable(true);
        setShowStatus(true);
        if(aConnectionItem.isSaveHistory() && aConnectionItem.getAppendMessages()>0 && jabberApp.getConn().isActive()){
            try {
                PreparedStatement st = jabberApp.getConn().prepareQuery("select INCOMING, MESSAGE_DATE, MESSAGE from HISTORY " +
                        "where LCASE(ACCOUNT)=? and LCASE(CONTACT)=? order by MESSAGE_DATE desc " +
                        "limit "+aConnectionItem.getAppendMessages());
                st.setString(1, fromUserName.toLowerCase());
                st.setString(2, toJID.toLowerCase());
                ResultSet rset = st.executeQuery();
                while(rset.next()){
                    ChatMessage message = new ChatMessage();
                    message.incoming = rset.getBoolean("incoming");
                    if(message.incoming){
                        message.from = toUserName;
                        message.to = fromUserName;
                    }else{
                        message.to = toUserName;
                        message.from = fromUserName;
                    }
                    message.connection = aConnectionItem.getId();
                    message.date = rset.getTimestamp("message_date");
                    message.message = rset.getString("message");
                    message.archive = true;
                    messages.add(0, message);
                }
                st.close();
            } catch (Throwable t) {
                Log.error(this, "Exception thrown: " + t.getMessage());
                t.printStackTrace();
            }
        }
//        setStatus("Characters: 0");
    }

    @RemoteMessage
    public void chatFocused(JSONObject aObject){
        jabberApp.setActiveChat(this);
        if(newMessages>0){
            newMessages = 0;
            updateTitle();
        }
        jabberApp.changeWorkspaceCaption(false);
    }

    @RemoteMessage
    public void chatUnFocused(JSONObject aObject){
        if(jabberApp.getActiveChat()==this)
            jabberApp.setActiveChat(null);
    }

    private void updateTitle(){
        if(newMessages>0)
            setTitle("["+newMessages+"] "+frameTitle);
        else
            setTitle(frameTitle);
    }

    public static String convertMessage(String message){
        message = SystemManager.prepareTextForView(message, true);
        Pattern urlPattern = Pattern.compile(URL_REGEXP2, Pattern.CASE_INSENSITIVE);
        Matcher m = urlPattern.matcher(message);
        StringBuffer sb = new StringBuffer();
        boolean found = false;
        while(m.find()){
            found = true;
//                Log.debug(this, "Found link at "+m.start()+" to "+m.end());
            String link = m.group();
            String link2 = new String(link);
            if(!link2.startsWith("http://") && !link2.startsWith("https://")){
                link2 = "http://"+link2;
            }
            if(link.length()>30){
                link = link.substring(0, 27)+"...";
            }
            m.appendReplacement(sb, "<a href=\""+link2+"\" class=\"tweet_link\" target=\"_blank\">"+link+"</a>");
        }
        m.appendTail(sb);
        return sb.toString();
    }

    @RemoteMessage
    public JSONObject sendMessage(JSONObject aObject){
        try {
            if(jabberApp.getRosterFrame().sendMessage(fromUserName, toJID, aObject.optString("message", frameTitle))){
                ChatMessage m = new ChatMessage();
                m.from = fromUserName;
                m.to = toJID;
                m.incoming = false;
                m.message = aObject.optString("message", frameTitle);
                newMessage(m, false);
            }else{
                return NetworkManager.getErrorObject(810, "Can't send message. Network error");
            }
        } catch (Throwable t) {
            Log.error(this, "Exception thrown: " + t.getMessage());
            t.printStackTrace();
        }
        return null;
    }

    private JSONObject messageToJSON(ChatMessage aMessage){
        try {
            JSONObject obj = new JSONObject();
            obj.put("from", SystemManager.prepareTextForView(aMessage.incoming?toUserName: connectionItem.getNickName(), true));
            obj.put("message", convertMessage(aMessage.message));
            obj.put("incoming", aMessage.incoming);
            obj.put("system", aMessage.system);
            obj.put("archive", aMessage.archive);
            obj.put("date", dateFormat.format(
                    jabberApp.getSession().normalizeDate(aMessage.date)));
            obj.put("mdate", aMessage.archive?
                mobileDateFormatArchived.format(jabberApp.getSession().normalizeDate(aMessage.date)):
                mobileDateFormat.format(jabberApp.getSession().normalizeDate(aMessage.date)));
            return obj;
        } catch (Throwable t) {
            Log.error(this, "Exception thrown: " + t.getMessage());
            t.printStackTrace();
        }
        return new JSONObject();
    }

    @RemoteMessage
    public JSONObject getHistory(JSONObject aData){
        try {
            JSONArray arr = new JSONArray();
            for (ChatMessage chatMessage : messages) {
                arr.put(messageToJSON(chatMessage));
            }
            JSONObject obj = new JSONObject();
            obj.put("history", arr);
            historyRequested = true;
            return obj;
        } catch (Throwable t) {
            Log.error(this, "Exception thrown: " + t.getMessage());
            t.printStackTrace();
        }
        return null;
    }

    public void newMessage(ChatMessage aMessage, boolean aNewMessage){
        ConnectionItem item = jabberApp.getRosterFrame().getConnectionItem(fromUserName);
        if(aNewMessage && item!=null && item.isShowNotify()){
            Notify notify = new Notify("Message from "+aMessage.from,
                    "New message from "+aMessage.from);
            notify.setIcon("jabber_t_icn jabber_t_main");
            jabberApp.addNotify(notify, this);
        }
        if(aNewMessage && (jabberApp.getActiveChat()!=this || !jabberApp.isWorkspaceActive())){
            newMessages++;
            jabberApp.changeWorkspaceCaption(true);
            updateTitle();
            if(newMessages==1 && historyRequested){
                ChatMessage systemMessage = new ChatMessage();
                systemMessage.message = "*** Unread messages:";
                systemMessage.system = true;
                messages.add(systemMessage);
                sendMessage("newMessage", messageToJSON(systemMessage));
            }
        }
        messages.add(aMessage);
        if(historyRequested)
            sendMessage("newMessage", messageToJSON(aMessage));
        try {
            if(item!=null && item.isSaveHistory() && jabberApp.getConn().isActive()){
                PreparedStatement st = jabberApp.getConn().prepareQuery("insert into history " +
                        "(account, contact, incoming, message_date, message) values " +
                        "(?, ?, ?, ?, ?)");
                st.setString(1, fromUserName);
                st.setString(2, toJID);
                st.setBoolean(3, aMessage.incoming);
                st.setTimestamp(4, new Timestamp(aMessage.date.getTime()));
                st.setString(5, aMessage.message);
                st.execute();
                st.close();
            }
        } catch (Throwable t) {
            Log.error(this, "Exception thrown: " + t.getMessage());
            t.printStackTrace();
        }
    }

    @Override
    public void terminate() {
        super.terminate();
        if(jabberApp.getActiveChat()==this)
            jabberApp.setActiveChat(null);
    }


}
